package server;

import gameframe.Chess;
import gameframe.ChessPanel;
import gameframe.GameFrame;

import javax.swing.*;
import java.awt.*;
import java.io.Serializable;
import java.util.LinkedList;

/**
 * @author Hsu琛君珩
 * @ClassName:Model
 * @date 2023-12-18
 * @apiNote
 * @Version: v1.0
 */

/**
 * 五子棋游戏的模型类，用于管理游戏状态。
 * 实现了Serializable接口，以便可以序列化和传输。
 */
public class Model extends Component implements Serializable {

    private static final int SPACE = 0; // 空位置的标记
    private static final int WIDTH = 15; // 棋盘宽度
    private final int[][] chessBoard = new int[WIDTH][WIDTH]; // 棋盘数组
    private LinkedList<Chess> chessStack; // 存储棋子的栈
    private String chatInfo; // 聊天信息
    private int winner = SPACE; // 获胜方标记
    private int regretChessColor; // 悔棋方的颜色
    private int surrenderChessColor; // 认输方的颜色

    /**
     * 构造函数，初始化棋子栈。
     */
    public Model() {
        chessStack = new LinkedList<>();
    }

    //获取棋子栈。
    public LinkedList<Chess> getChessStack() {
        return chessStack;
    }
    //获取聊天信息。
    public String getChatInfo() {
        return chatInfo;
    }
    //获取棋盘数组。
    public int[][] getBoard() {
        return chessBoard;
    }
    //获取获胜方。
    public int getWinner() {
        return winner;
    }

    //设置获胜方。
    public void setWinner(int winChessColor) {
        this.winner = winChessColor;
        this.surrenderChessColor = Chess.SPACE;
    }
    //获取认输方的颜色。
    public int getSurrenderChessColor() {
        return surrenderChessColor;
    }
    //设置认输方的颜色。
    public void setSurrenderChessColor(int surrenderChessColor) {
        this.surrenderChessColor = surrenderChessColor;
    }
    //获取悔棋方的颜色。
    public int getRegretChessColor() {
        return regretChessColor;
    }
    //设置悔棋方的颜色。
    public void setRegretChessColor(int regretChessColor) {
        this.regretChessColor = regretChessColor;
    }

    /**
     * 下棋操作：在棋盘上放置一个新棋子，并将其加入到棋子栈中。
     * 此方法创建一个新的棋子对象并更新棋盘数组以及棋子栈，以记录下棋的位置和颜色。
     *
     * @param chessColor 棋子颜色，用于区分黑棋和白棋。
     * @param x 棋子的横坐标，指定放置棋子的列。
     * @param y 棋子的纵坐标，指定放置棋子的行。
     */
    public void putChess(int chessColor, int x, int y) {
        Chess chess = new Chess(x, y, chessColor); // 创建新棋子
        chessBoard[x][y] = chessColor; // 更新棋盘数组
        chessStack.add(chess); // 将新棋子加入棋子栈
    }

    /**
     * 悔棋操作：从棋子栈中移除最后两个棋子。
     * 此方法用于实现悔棋功能，它会移除棋子栈中最后的两个棋子并更新棋盘状态。
     */
    public void regretChess() {
        if (chessStack.size() < 2) {
            //JOptionPane.showMessageDialog(GameFrame.getInstance(), "食懵你啊！", "悔棋错误", JOptionPane.WARNING_MESSAGE);
            return; // 当棋子栈中少于两个棋子时不进行悔棋操作
        }
        // 移除最后一个棋子并更新棋盘
        Chess chess = chessStack.removeLast();
        chessBoard[chess.getPosX()][chess.getPosY()] = SPACE;
        // 再移除前一个棋子并更新棋盘
        chess = chessStack.removeLast();
        chessBoard[chess.getPosX()][chess.getPosY()] = SPACE;
    }

    /**
     * 检查坐标是否在棋盘范围内。
     * 用于确保棋子放置的位置不超出棋盘的边界。
     *
     * @param curX x坐标
     * @param curY y坐标
     * @return 坐标是否在棋盘范围内，true表示在范围内，false表示超出范围。
     */
    public boolean checkIndex(int curX, int curY) {
        return curX >= 0 && curX < WIDTH && curY >= 0 && curY < WIDTH;
    }

    /**
     * 检查下棋位置是否合理。
     * 确保下棋的位置不仅在棋盘范围内，而且是空的，没有其他棋子。
     *
     * @param curX x坐标
     * @param curY y坐标
     * @return 下棋位置是否合理，true表示位置合理，false表示位置不合理或已被占用。
     */
    public boolean checkIndex(int curX, int curY, int i) {
        return curX >= 0 && curX < WIDTH && curY >= 0 && curY < WIDTH && chessBoard[curX][curY] == SPACE;
    }

    /**
     * 更新聊天信息。
     * 将新的聊天信息添加到现有的聊天信息中，每条消息前附上发送者的用户名。
     *
     * @param userName 发送聊天信息的用户名
     * @param chatStr  聊天信息内容
     */
    public void updateChatInfo(String userName, String chatStr) {
        StringBuilder builder = new StringBuilder();
        if (chatInfo != null) {
            builder.append(chatInfo).append('\n'); // 添加现有聊天信息
        }
        builder.append(userName).append(": ").append(chatStr); // 添加新聊天信息
        chatInfo = builder.toString(); // 更新聊天信息
    }

}
